package example.hello_security.config.filter;

import cn.hutool.json.JSONUtil;
import example.hello_security.config.JwtConfig;
import example.hello_security.config.WebConfig;
import example.hello_security.entity.LoginsUserDetail;
import example.hello_security.service.RedisStore;
import example.hello_security.utils.JwtUtil;
import io.lettuce.core.RedisClient;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Objects;

/**
 * 自定义一个filter，进行对token验证的支持
 * 目的是将client拥有的token进行验证交给security的上下文，进行校验，然后实现对接口的访问授权
 * description 对filter的实现,使用OncePerRequestFilter抽象类，官方提供的filter类作为基础进行实现
 *
 * @author zken
 * CreateDate 2024/10/27 20:06:45
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    JwtConfig jwtConfig;

    @Resource
    RedisStore redisStore;

    @Resource
    WebConfig webConfig;
    //    实现这个类OncePerRequestFilter中的未实现方法

    /**
     * description redis持久化验证token的办法
     * @author zken
     * CreateDate 2024/10/27 20:26:41
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader(webConfig.getTokenName());
        // 如果存在这个token
        if (StringUtils.isNotBlank(token)) {
            String key = jwtConfig.jwtRedisKeyPrefix + token;
            String json = redisStore.get(key);
            if (StringUtils.isNotBlank(json)) {
                LoginsUserDetail userDetail = JSONUtil.toBean(json, LoginsUserDetail.class);
                if (Objects.nonNull(userDetail)) {
                    // credential是密码，这里由于已经存在了令牌所有可以为空
                    UsernamePasswordAuthenticationToken authenticationToken =
                            new UsernamePasswordAuthenticationToken(userDetail, null, userDetail.getAuthorities());
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                } else {
                    // 如果redis中已经不再记录此token，直接设置为空
                    SecurityContextHolder.getContext().setAuthentication(null);
                }
            }
        }
        // 继续执行filter
        filterChain.doFilter(request, response);
    }
}
